package view 
{
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import model.ArrayBuilder;
	import model.Board;
	import model.Constants;
	import model.observer.IView;
	import model.Point;
	import model.Utils;
	/**
	 * ...
	 * @author Yang Wang
	 */
	public class BoardView extends Sprite implements IView	
	{
		private var m_board: Board;
		private var m_gridArray:Array;
		
		private var m_background: Sprite;
		private var m_grid:Sprite;
		private var m_shape:ShapeView;
		private var m_ghost:GhostView;
		
		public function BoardView(board:Board) 
		{
			this.m_board = board;
			this.m_board.addView(this);
			this.m_gridArray = new ArrayBuilder().build2DArray(m_board.width, m_board.height);
			
			this.m_background = this.getBoardBackground();
			this.m_grid = new Sprite();
			this.m_shape = new ShapeView(m_board.currentShape);
			
			this.drawBoard();
		}
		
		private function drawBoard() : void {
			// a board would have a few components in it.
			
			// 1. the background grid
			this.addChild(background);
			this.addChild(grid);
			this.updateCurrentShape();
		}
		
		private function updateCurrentShape(hasNewShape:Boolean = false) : void {
			if (m_shape == null || this.m_board.currentShape == null) {
				return;
			}
			
			if(this.contains(m_shape))
				this.removeChild(m_shape);
				
			if (hasNewShape) {
				m_shape = new ShapeView(m_board.currentShape);
			}
			
			this.addChild(m_shape);
			this.setPositionInBoard(m_shape, m_board.shapePosition);
			

			this.updateGhost();
		}
		
		public function updateGhost() : void {
			if (m_ghost==null || m_ghost.parentShape() != this.m_board.currentShape) {				
				// create a new ghost
				if (this.m_ghost != null && this.contains(m_ghost))
					this.removeChild(m_ghost);
				
				m_ghost = new GhostView(this.m_board.currentShape, new Square(0));
				this.addChildAt(m_ghost, this.getChildIndex(m_shape) -1);
			}
			var ghostPosition:Point = this.m_board.getHardDropFinalLocation();
			this.setPositionInBoard(m_ghost, ghostPosition);			
		}
		
		private function updateGridSprite(): Sprite {
			var grid:Sprite = new Sprite();
			for (var i:int = 0; i < m_board.width; i++) {
				for (var j:int = 0; j < m_board.height; j++) {
					var point:Point = new Point(i, j);
					if (m_board.isFilled(point)) {
						if(this.m_gridArray[i][j]==null) {
							addSquareToGrid(point);
						}
					} else {
						if (this.m_gridArray[i][j] != null) {
							removeSquareFromGrid(point);
						}
					}
				}
			}
			return grid;
		}
		
		private function addSquareToGrid(point:Point): void {
			var square:Square = new Square(m_board.getCell(point.X,point.Y));
			grid.addChild(square);
			this.setPositionInBoard(square, point);
			this.m_gridArray[point.X][point.Y] = square;
		}
		
				
		private function removeSquareFromGrid(point:Point): void {
			grid.removeChild(m_gridArray[point.X][point.Y]);
			m_gridArray[point.X][point.Y] = null;
		}
		
		private function setPositionInBoard(displayObj: DisplayObject, point:Point) : void
		{
			displayObj.x = point.X *  Constants.SQUARE_DIMENSION;
			displayObj.y = (m_board.height - point.Y - 1) * Constants.SQUARE_DIMENSION;
		}
		
		private function getBoardBackground() : Sprite {
			
			var background:Sprite = new Sprite();
			var bgGraphics:Graphics = background.graphics;
			
			bgGraphics.lineStyle(2, 0x666666);
			
			for (var i:int = 0; i <= m_board.width; i++) {
				bgGraphics.moveTo(i * Constants.SQUARE_DIMENSION, 0);
				bgGraphics.lineTo(i * Constants.SQUARE_DIMENSION, m_board.height * Constants.SQUARE_DIMENSION);
			}
			
			for (var j:int = 0; j <= m_board.height; j++) {
				bgGraphics.moveTo(0, j * Constants.SQUARE_DIMENSION);
				bgGraphics.lineTo(m_board.width * Constants.SQUARE_DIMENSION, j * Constants.SQUARE_DIMENSION);
			}
			
			for (i = 0; i < m_board.width; i++) {
				for (j= 0; j < m_board.height; j++) {
					var color:uint = 0xaaaaaa;
					if ((i + j) % 2 == 0) 
						color = 0xcccccc;
					
					bgGraphics.beginFill(color);
					bgGraphics.drawRect(i * Constants.SQUARE_DIMENSION, j * Constants.SQUARE_DIMENSION, Constants.SQUARE_DIMENSION, Constants.SQUARE_DIMENSION);
					bgGraphics.endFill();
				}
			}
			
			return background;
		}
		
		private function updateGraphics() : void  {
			
			updateGridSprite();
		}
		/* INTERFACE model.observer.IView */
		
		public function updateView(obj:Object):void 
		{
			updateGridSprite();
			this.updateCurrentShape(obj.newShape);
		}
		
		public function get background():Sprite 
		{
			return m_background;
		}
		
		public function set background(value:Sprite):void 
		{
			m_background = value;
		}
		
		public function get grid():Sprite 
		{
			return m_grid;
		}
		
		public function set grid(value:Sprite):void 
		{
			m_grid = value;
		}
		
	}

}